package org.jflame.devAide.plugin.websocket;

import org.jflame.commons.util.StringHelper;
import org.jflame.devAide.service.ThreadService;

import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;

import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.controlsfx.validation.decoration.StyleClassValidationDecoration;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.handshake.ServerHandshake;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class WebsocketTestController implements Closeable {

    @FXML
    private TextField txfServerUrl;
    @FXML
    private TextArea txaSendMsg;
    @FXML
    private TextArea txaConsole;
    @FXML
    private Button btnConnect;
    @FXML
    private Button btnDisconnect;
    @FXML
    private Button btnSend;

    private ValidationSupport validationSupport = new ValidationSupport();
    private MyWebsocketClient wsclient;

    @FXML
    protected void initialize() {
        validationSupport.setValidationDecorator(new StyleClassValidationDecoration());
        validationSupport.registerValidator(txfServerUrl, Validator.createRegexValidator("不是正确的websocket地址",
                "(https?|ftp|file|wss?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]", null));

        // 加个右键菜单清空输出面板内容
        MenuItem item = new MenuItem("清空");
        item.setOnAction(event -> {
            txaConsole.clear();
        });
        ContextMenu consoleMenu = new ContextMenu(item);
        txaConsole.setContextMenu(consoleMenu);
    }

    @Override
    public void close() throws IOException {
        if (wsclient != null && wsclient.isOpen()) {
            wsclient.close();
        }
        wsclient = null;
    }

    @FXML
    private void handleConnect(ActionEvent event) {
        String wsUrl = txfServerUrl.getText();
        if (StringHelper.isEmpty(wsUrl)) {
            return;
        }
        URI wsUri = null;
        try {
            wsUri = new URI(wsUrl);
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return;
        }
        btnConnect.setDisable(true);
        if (wsclient == null) {
            wsclient = new MyWebsocketClient(wsUri);
        } else {
            if (wsclient.isOpen()) {
                try {
                    outlog("正在关闭连接");
                    wsclient.closeBlocking();
                } catch (InterruptedException e) {
                    wsclient = null;
                }
            }
            wsclient = new MyWebsocketClient(wsUri);
        }
        outlog("开始连接");
        ThreadService.instance()
                .run(() ->
                {
                    boolean isOk = false;
                    try {
                        isOk = wsclient.connectBlocking(30, TimeUnit.SECONDS);
                        // System.out.println("连接..." + isOk);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isOk) {
                        Platform.runLater(() -> {
                            // System.out.println("dd false");
                            outlog("连接失败");
                            btnConnect.setDisable(false);
                        });
                    }
                });

    }

    @FXML
    private void handleDisconnect(ActionEvent event) {
        if (wsclient != null && wsclient.getReadyState() == ReadyState.OPEN) {
            wsclient.close();
        }
        if (btnConnect.isDisabled()) {
            btnConnect.setDisable(false);
        }
    }

    @FXML
    private void handleSendMsg(ActionEvent event) {
        String sendMsg = txaSendMsg.getText();
        if (StringHelper.isEmpty(sendMsg)) {
            return;
        }
        if (wsclient == null || !wsclient.isOpen()) {
            outlog("请先开启连接");
            return;
        }

        wsclient.send(sendMsg);
        txaConsole.appendText("客户端 > " + sendMsg + "\n");
        txaSendMsg.clear();
    }

    private void outlog(String log) {
        txaConsole.appendText("> " + log + "\n");
    }

    private class MyWebsocketClient extends WebSocketClient {

        public MyWebsocketClient(URI serverUri) {
            super(serverUri);
            setConnectionLostTimeout(30);
        }

        private final String closeMsgTpl = "%s关闭连接, 错误码:%d, %s";

        @Override
        public void onClose(int arg0, String arg1, boolean arg2) {
            if (arg0 == CloseFrame.PROTOCOL_ERROR) {
                arg1 = "请确认地址或协议正确";
            } else if (arg0 == CloseFrame.NORMAL) {
                arg1 = "正常关闭";
            }

            out(String.format(closeMsgTpl, arg2 ? "服务端" : "", arg0, arg1));
            txaConsole.appendText("-----------------\n");
            btnConnect.setDisable(false);
        }

        @Override
        public void onError(Exception ex) {
            out("发生错误:" + ex.getMessage());
        }

        @Override
        public void onMessage(String arg0) {
            ThreadService.instance()
                    .runActionLater(x -> txaConsole.appendText("服务端 > " + arg0 + "\n"));
        }

        @Override
        public void onOpen(ServerHandshake arg0) {
            out("已连接:" + getURI());
        }

        private void out(String content) {
            ThreadService.instance()
                    .runActionLater(x -> txaConsole.appendText("> " + content + "\n"));
        }
    }
}
